package com.xtinno.service.impl;

import cn.hutool.ai.core.Message;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.hubspot.jinjava.Jinjava;
import com.xtinno.common.JsonKeyChineseToPinyin;
import com.xtinno.common.MDCUtils;
import com.xtinno.config.ConfigCenter;
import com.xtinno.dal.dto.WorkflowDefinitionModel;
import com.xtinno.dal.dto.WorkflowModel;
import com.xtinno.dal.service.IWorkflowDefinitionService;
import com.xtinno.dal.service.IWorkflowService;
import com.xtinno.dal.service.SysCaseCauseService;
import com.xtinno.dal.service.impl.WorkflowBaseServiceImpl;
import com.xtinno.models.WorkFlowOutput;
import com.xtinno.models.WorkFlowRequestModel;
import com.xtinno.models.WorkFlowResultModel;
import com.xtinno.models.openai.ResponseOpenAiModel;
import com.xtinno.service.WorkFowService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 工作流实现的默认业务类
 */
@Slf4j
@Service("WorkFlowServiceImpl")
@RequiredArgsConstructor
@Scope("prototype")
public class WorkFlowServiceImpl implements WorkFowService {
	protected final WorkflowBaseServiceImpl workflowBaseService;
	protected final IWorkflowService workflowService;
	protected final IWorkflowDefinitionService workflowDefinitionService;
	protected final ConfigCenter configCenter;

	@Autowired
	private SysCaseCauseService caseCauseService;
	@Autowired
	private SysCaseCauseService sysCaseCauseService;

	/**
	 * 根据输入参数初始化全局map参数
	 *
	 * @param variables
	 * @return
	 */
	private Map<String, Object> InitMap(Object variables) {
		JSONObject jsonObject = (JSONObject) JSON.toJSON(variables);
		Map<String, Object> map = new HashMap<String, Object>();
		for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
			map.put("start_" + entry.getKey().toLowerCase(), entry.getValue());
		}
		return map;
	}

	/**
	 * 执行工作流
	 *
	 * @param workFlowRequestModel 动态入参
	 * @return
	 */
	@Override
	public WorkFlowResultModel RunWorkFlow(WorkFlowRequestModel workFlowRequestModel) {
		WorkFlowResultModel workFlowResultModel = new WorkFlowResultModel();
		workFlowResultModel.setTaskId(MDCUtils.getTraceId());
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date startDate = new Date();
		workFlowResultModel.setCreatedAt(formatter.format(startDate));
		workFlowResultModel.setWorkflowId(workFlowRequestModel.getWorkflowId());
		Map<String, Object> gloabMap = InitMap(workFlowRequestModel.getInputs().getVariables());//全局使用
		JSONObject defaultParam = workflowBaseService.GetDefaultLlmParam();
		var workflow = workflowService.lambdaQuery().eq(WorkflowModel::getCWfWorkflowId, workFlowRequestModel.getWorkflowId()).one();
		if (workflow == null) {
			throw new RuntimeException("工作流不存在");
		}
		var result = StepRun(workFlowRequestModel, defaultParam, gloabMap);
		var output = new WorkFlowOutput();
		output.setText(result);
		workFlowResultModel.setOutputs(output);
		workFlowResultModel.setInputTokens((Integer) gloabMap.getOrDefault("inputTokens", 0));
		workFlowResultModel.setOutputTokens((Integer) gloabMap.getOrDefault("outputTokens", 0));
		workFlowResultModel.setTotalTokens((Integer) gloabMap.getOrDefault("totalTokens", 0));
		Date endData = new Date();
		workFlowResultModel.setElapsedTime(endData.getTime() - startDate.getTime());
		workFlowResultModel.setFinishedAt(formatter.format(endData));
		log.info("工作流执行-完成", workFlowResultModel);
		return workFlowResultModel;
	}

	/**
	 * 步数执行
	 *
	 * @param workFlowRequestModel
	 * @param defaultParam
	 * @param gloabMap
	 * @return
	 */
	protected String StepRun(WorkFlowRequestModel workFlowRequestModel, JSONObject defaultParam, Map<String, Object> gloabMap) {
		var workflowDetail = workflowDefinitionService.lambdaQuery().eq(WorkflowDefinitionModel::getCWfWorkflowId, workFlowRequestModel.getWorkflowId()).list();
		var firstWork = workflowDetail.stream().filter(p -> "1".equals(p.getCWfdStepStart())).findFirst().get();
		var result = RunWorkStep(firstWork, defaultParam, gloabMap, workflowDetail);
		return result;
	}

	/**
	 * 单步执行
	 *
	 * @param workflowDefinitionModel
	 * @param defaultParam
	 * @param gloabMap
	 */
	protected String RunWorkStep(WorkflowDefinitionModel workflowDefinitionModel, JSONObject defaultParam, Map<String, Object> gloabMap, List<WorkflowDefinitionModel> workflowDetail) {
		var result = "";
		log.info("工作流执行-开始{}", JSONObject.toJSONString(workflowDefinitionModel));
		switch (workflowDefinitionModel.getCWfdStepType()) {
			case "llm":
				result = RunLlm(workflowDefinitionModel, defaultParam, gloabMap, 0);
				break;
			case "replacechinakey":
				ReplaceChinaKey(workflowDefinitionModel, gloabMap);
				break;
			case "postProcessCause":
				postProcessCauseExtractFillCcIdAndCcExplain(workflowDefinitionModel, gloabMap);
				break;
			case "end":
				return EndDeal(workflowDefinitionModel, gloabMap);
			default:
				break;
		}
		//读取下一个执行
		var nextWork = workflowDetail.stream().filter(p -> workflowDefinitionModel.getCWfdStepId().equals(p.getCWfdStepParent())).findFirst().orElse(null);
		if (nextWork == null) {
			return result;
		}
		return RunWorkStep(nextWork, defaultParam, gloabMap, workflowDetail);
	}

	private String EndDeal(WorkflowDefinitionModel workflowDefinitionModel, Map<String, Object> gloabMap) {
		var t1 = workflowDefinitionModel.getCWfdFunctionInput();
		Jinjava jinjava = new Jinjava();
		t1 = jinjava.render(t1, gloabMap);
		return t1;
	}

	private void ReplaceChinaKey(WorkflowDefinitionModel workflowDefinitionModel, Map<String, Object> gloabMap) {
		var r1 = gloabMap.get(workflowDefinitionModel.getCWfdFunctionInput());
		var obj = JSONObject.parseObject((String) r1);
		gloabMap.put(workflowDefinitionModel.getCWfdStepId() + "_result", JSONObject.toJSONString(JsonKeyChineseToPinyin.convertJsonKeys(obj)));
	}

	/**
	 * 案由 补充 id  和 释义.
	 * @param workflowDefinitionModel .
	 * @param globalMap .
	 */
	private void postProcessCauseExtractFillCcIdAndCcExplain(WorkflowDefinitionModel workflowDefinitionModel, Map<String, Object> globalMap) {
		String a01_result = globalMap.get("a01_result").toString();

		// 1. 解析字符串为 JSONArray
		JSONArray array = JSON.parseArray(a01_result);

		// 2. 遍历每个元素（JSONObject）
		for (int i = 0; i < array.size(); i++) {
			JSONObject obj = array.getJSONObject(i);
			if (obj != null) {
				// 3. 获取 "案由" 字段
				String ay = obj.getString("案由");
				if (ay != null) {
					// 4. 调用 查询案由 方法
					var caseCause0 = sysCaseCauseService.findByNameAndAllParentIdPrefix(ay, "1477,");
					if (caseCause0.isPresent()) {
						obj.put("案由释义", caseCause0.get().getCc_explain());
						obj.put("案由编号", caseCause0.get().getCc_id());
					}
				}
			}
		}

		JSONObject wrapper = new JSONObject();
		wrapper.put("cause", array);

		// 5. 序列化为 JSON 字符串（可选美化格式）
		globalMap.put(workflowDefinitionModel.getCWfdStepId() + "_result", JSON.toJSONString(wrapper));
	}

	/**
	 * 请求大模型
	 *
	 * @param defaultParam
	 * @param gloabMap
	 * @param runNum
	 * @return
	 */
	private String RunLlm(WorkflowDefinitionModel workflowDefinitionModel, JSONObject defaultParam, Map<String, Object> gloabMap, int runNum) {
		var url = configCenter.getLlmUrl() + "/v1/chat/completions";
		JSONObject param;
		if (StringUtils.isNotEmpty(workflowDefinitionModel.getCWfdLlmModelParams())) {
			param = JSONObject.parseObject(workflowDefinitionModel.getCWfdLlmModelParams());
		}
		else {
			param = defaultParam;
		}
		List<Message> messages = new ArrayList<>();
		if (StringUtils.isNotEmpty(workflowDefinitionModel.getCWfdLlmPromptTemplateSystem())) {
			var t1 = workflowDefinitionModel.getCWfdLlmPromptTemplateSystem();
			Jinjava jinjava = new Jinjava();
			t1 = jinjava.render(t1, gloabMap);
			messages.add(new Message("system", t1));
		}
		if (StringUtils.isNotEmpty(workflowDefinitionModel.getCWfdLlmPromptTemplateUser())) {
			var t1 = workflowDefinitionModel.getCWfdLlmPromptTemplateUser();
			Jinjava jinjava = new Jinjava();
			t1 = jinjava.render(t1, gloabMap);
			messages.add(new Message("user", t1));
		}
		param.put("messages", messages);
		if (StringUtils.isNotEmpty(workflowDefinitionModel.getCWfdLlmModelJsonSchema())) {
			param.put("guided_json", workflowDefinitionModel.getCWfdLlmModelJsonSchema());
		}
		String json = JSONObject.toJSONString(param);
		//链式构建请求
		try {
			log.info("工作流执行-请求大模型:{},参数:{}", url, json);
			String result = HttpRequest.post(url)
					.body(json)
					.timeout(600000)//超时，毫秒
					.execute().body();
			log.info("工作流执行-请求大模型结果:{}", result);
			var obj = JSONObject.parseObject(result, ResponseOpenAiModel.class);
			var content = obj.getChoices().get(0).getMessage().getContent();
			String[] split = content.split("</think>");
			if (split.length > 1) {
				gloabMap.put(workflowDefinitionModel.getCWfdStepId() + "_thinkresult", split[0].replace("<think>", ""));
			}
			var jsonResult = split[split.length - 1].replace("`json", "").replace("`", "");
			gloabMap.put(workflowDefinitionModel.getCWfdStepId() + "_result", jsonResult);
			var inputTokens = gloabMap.getOrDefault("inputTokens", 0);
			var outputTokens = gloabMap.getOrDefault("outputTokens", 0);
			var totalTokens = gloabMap.getOrDefault("totalTokens", 0);
			gloabMap.put("inputTokens", (Integer) inputTokens + obj.getUsage().getPrompt_tokens());
			gloabMap.put("outputTokens", (Integer) outputTokens + obj.getUsage().getCompletion_tokens());
			gloabMap.put("totalTokens", (Integer) totalTokens + obj.getUsage().getTotal_tokens());
			return jsonResult;
		}
		catch (Exception exception) {
			log.error("工作流执行-请求大模型异常", exception);
			if (runNum > 0) {
				throw exception;
			}
			else {
				return RunLlm(workflowDefinitionModel, defaultParam, gloabMap, runNum++);
			}
		}
	}
}
